import { SETTINGS, WORDS } from "./model/WORDS.js";
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { PerspectiveCamera, Mesh, Raycaster, Scene, Vector2, WebGLRenderer, Group, Object3D, Vector3, BufferGeometry, Material, Color, BoxGeometry, MeshBasicMaterial, DoubleSide, SphereGeometry } from 'three';
import { mergeGeometries } from "three/addons/utils/BufferGeometryUtils.js";


import { OutlinePass } from 'three/addons/postprocessing/OutlinePass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
// import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
// import { FXAAShader } from "three/addons/shaders/FXAAShader.js";

// import { FXAAShader } from "three/addons/shaders/FXAAShader.js";
// import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';




import { GLTFExporter } from "three/addons/exporters/GLTFExporter.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { Helper } from './helper.js';
// import ModelConnection from "./model/modelConnection.js";
import Platform from "./model/platform.js";
import { DataLine, DataLineParams } from "./model/dataLine.js";
import Frame from "./model/frame.js";
import { Device, DeviceParams } from "./model/device.js";
import { Plane } from "./model/plane.js";
import { Line2 } from 'three/addons/lines/Line2.js';

import { LineGeometry } from 'three/addons/lines/LineGeometry.js';
import { LineMaterial } from 'three/addons/lines/LineMaterial.js';
import GUIController from './gui.js';

let camera: PerspectiveCamera, scene: Scene, renderer: WebGLRenderer, controls: OrbitControls;
let pointer: Vector2, raycaster: Raycaster;

const link: HTMLAnchorElement = document.createElement('a')
var loader = new GLTFLoader()

class main {

	_canvas: HTMLCanvasElement
	_gui: GUIController | undefined

	_curModel: Group | null | Mesh | Object3D;
	_mousemoveObj?: Object3D;
	_mousemoveModel2: Group | null | Mesh | Object3D;

	// 添加设备时悬浮物
	/**
	 * 对象设为undefined，其属性并不会undefined，可能存在内存泄漏
	 */
	_thatsAddingDevice: {
		params: DeviceParams | undefined,
		obj: Mesh<BoxGeometry, MeshBasicMaterial> | undefined
	}
	// 添加连线时悬浮物
	_thatsAddingDataLine: {
		params: DataLineParams | undefined, // 初始化参数
		sphere: Mesh<SphereGeometry, MeshBasicMaterial> | undefined // 悬浮球
		bodyLine: Line2 | undefined // 主体线
		headLine: Line2 | undefined // 头部线
	}


	// 辅助平台层（hide）
	_aidedPlane: Mesh | null
	// 高亮辅助线
	_aidedLine4highlight?: Line2
	// 选中辅助线
	_aidedLine4selected?: Line2


	_selectedModel: DataLine | Device | null

	_mousemoveEventInstance: null | ((event: MouseEvent) => void)
	_clickEventInstance: null | ((event: MouseEvent) => void)
	_dblclickEventInstance: null | ((event: MouseEvent) => void)
	_keyUpEventInstance: null | ((event: KeyboardEvent) => void)

	_curOperation: '' | 'addDevice' | 'addDataLine' //  'editWirFrame' |
	_frame = new Frame()

	_curPlatform: Platform | undefined

	// 边界发光
	_outlinePass: OutlinePass | null;
	_outlinePassS: OutlinePass | null;
	_composer: EffectComposer | null;
	_renderPass: RenderPass | null

	constructor(containerId = "container") {
		this._thatsAddingDataLine = {
			params: undefined,
			bodyLine: undefined,
			sphere: undefined,
			headLine: undefined,
		}

		this._thatsAddingDevice = {
			obj: undefined,
			params: undefined
		}


		this._curModel = null
		this._mousemoveModel2 = null
		this._aidedPlane = null
		this._mousemoveEventInstance = null
		this._clickEventInstance = null
		this._dblclickEventInstance = null
		this._keyUpEventInstance = null

		this._selectedModel = null
		// this._mousemoveEventWhenWireFrame = null
		// this._dblClickEventWhenWireFrame = null

		// this._platform = null
		this._curOperation = ''


		// 边界发光
		this._outlinePass = null
		this._outlinePassS = null
		this._composer = null
		this._renderPass = null

		// 导出下载时使用
		link.style.display = 'none';
		document.body.appendChild(link);


		this._canvas = document.getElementById(containerId) as HTMLCanvasElement

	}

	/**
	 * 初始化
	 */
	init() {
		const me = this

		scene = new THREE.Scene();
		// scene.background = new THREE.Color('black')


		renderer = new THREE.WebGLRenderer({
			canvas: me._canvas,
			antialias: true
		})

		me._canvas.onmousemove = this._mousemoveEvent.bind(this)
		me._canvas.onclick = this._clickEvent.bind(this)
		me._canvas.ondblclick = this._dblclickEvent.bind(this)
		me._canvas.onkeyup = this._keyupEvent.bind(this)

		const canvasWidth = me._canvas.clientWidth
		const canvasHeight = me._canvas.clientHeight

		renderer.setClearColor(0x000000)
		renderer.setPixelRatio(window.devicePixelRatio)
		renderer.setSize(canvasWidth, canvasHeight)
		camera = new THREE.PerspectiveCamera(45, canvasWidth / canvasHeight, 1, 10000)
		camera.position.set(250, 400, 650)
		camera.lookAt(0, 0, 0)

		controls = new OrbitControls(camera, renderer.domElement)
		controls.update()

		//

		raycaster = new THREE.Raycaster()
		pointer = new THREE.Vector2()

		me._composer = new EffectComposer(renderer);

		const renderPass = new RenderPass(scene, camera);
		me._composer.addPass(renderPass);

		// 悬浮边界发光
		me._outlinePass = new OutlinePass(new THREE.Vector2(canvasWidth, canvasHeight), scene, camera)
		me._outlinePass.edgeStrength = 2; // 辉光强度
		me._outlinePass.edgeGlow = 1; // 辉光大小
		me._outlinePass.edgeThickness = 2; // 辉光厚度
		me._outlinePass.pulsePeriod = 0; // 周期性变化效果（设置为0表示没有周期性变化）
		const visibleColor = new THREE.Color(0, 1, 1); // 红色
		// const hiddenColor = new THREE.Color(0, 1, 0); // 绿色
		me._outlinePass.visibleEdgeColor.copy(visibleColor);
		// me._outlinePass.hiddenEdgeColor.copy(hiddenColor);
		me._composer.addPass(me._outlinePass);


		// 选中发光
		me._outlinePassS = new OutlinePass(new THREE.Vector2(canvasWidth, canvasHeight), scene, camera)
		me._outlinePassS.edgeStrength = 2; // 辉光强度
		me._outlinePassS.edgeGlow = 2; // 辉光大小
		me._outlinePassS.edgeThickness = 2; // 辉光厚度
		me._outlinePassS.pulsePeriod = 0; // 周期性变化效果（设置为0表示没有周期性变化）
		// const visibleColor = new THREE.Color(0, 1, 1); // 红色
		// const hiddenColor = new THREE.Color(0, 1, 0); // 绿色
		me._outlinePassS.visibleEdgeColor.copy(new THREE.Color(0, 1, 1));
		// me._outlinePass.hiddenEdgeColor.copy(hiddenColor);
		me._composer.addPass(me._outlinePassS);

		const outputPass = new OutputPass();
		me._composer.addPass(outputPass)

		me.resetScene()
		me._render()


		window.onresize = this._onWindowResize.bind(this)

		// GUI
		this._gui = new GUIController("gui")


		// 创建场景和相机





	}

	/**
	 * 导入模型
	 * @param url 
	 * @param name 
	 * @param scale 
	 */
	addModel(url: string, name: string, scale = 1) {
		const me = this
		me.stopOperate()
		me._curOperation = 'addDevice'
		loader.load(url, function (gltf) {

			// 创建一个新的 Mesh
			var mergedMesh = new Mesh();
			const materials: Material[] = []
			const geos: BufferGeometry[] = []

			// 遍历模型的子对象
			gltf.scene.children[0].traverse(function (child) {
				if (Object.prototype.hasOwnProperty.call(child, "isMesh")) {
					// 合并子对象为一个整体的 Mesh
					const childMesh = (child as Mesh)
					// let matrixWorldGeometry = childMesh.geometry.clone().applyMatrix4(childMesh.matrixWorld);
					//这个时候 matrixWorldGeometry 几何体的位置就已经转化成世界坐标的位置了

					geos.push(childMesh.geometry.clone())
					// mergedMesh.geometry.merge(childMesh.geometry, childMesh.matrix);
					materials.push(childMesh.material as Material)
				}
			})

			let merged = mergeGeometries(geos, true)

			// merged.applyMatrix4(gltf.scene.children[0].matrixWorld)
			mergedMesh.geometry = merged
			mergedMesh.material = materials

			mergedMesh.scale.set(scale, scale, scale)
			// 针对测试的glb，对gltf.scene子节点group，进行同样的旋转位置调整
			mergedMesh.rotation.copy(gltf.scene.children[0].rotation)
			me._curModel = null
			me._curModel = mergedMesh
			me._curModel.name = name
			me._mousemoveObj = Helper.deepClone(me._curModel);
			Helper.setMeshMaterialOpacity(me._mousemoveObj as Mesh, 0.5)
			scene.add(me._mousemoveObj)
		})
	}

	addDevice(params: DeviceParams) {
		const me = this
		me.stopOperate()
		me._curOperation = 'addDevice'
		me.showhideAidedObjs(true)

		const boxGeo = new BoxGeometry(params.width, params.height, params.depth)
		boxGeo.translate(0, params.height / 2, 0)
		const material = new MeshBasicMaterial({
			color: params.color,
			transparent: true,
			opacity: 0.5
		})
		const mesh = new Mesh(boxGeo, material)
		me._thatsAddingDevice = {
			params,
			obj: mesh
		}
		scene.add(mesh)
	}

	/**
	 * 导出场景
	 */
	exportScene() {
		const me = this
		me.stopOperate()


		// 隐藏辅助类obj
		// me.removeObj((name) => { return !name.startsWith(WORDS.OBJNAME.MODEL_PREFIX) })
		scene.traverse(i => {
			if (i.userData.type === WORDS.OBJNAME.HELPER_PREFIX || i.userData.type === WORDS.OBJNAME.MODEL_DATALINE) {
				i.visible = false
			}
		})

		//   初始化Exporter，初始化一遍即可：
		let igltfexporter = new GLTFExporter();
		//  导出gltf模型配置：
		const exPortOptions = {
			//true导出位置、缩放、旋转变换，false导出节点的矩阵变换
			trs: false,
			//是否只导出可见的
			onlyVisible: true,
			truncateDrawRange: true,
			//是否二进制，true导出glb模型，false导出gltf模型
			binary: true,
			//最大贴图尺寸
			maxTextureSize: Infinity,
			// 包含自定义信息
			// includeCustomExtensions: true
		}

		igltfexporter.parse(
			scene,
			(result) => {
				//result即是gltf文件，写入到本地
				if (result instanceof ArrayBuffer) {
					me.save(new Blob([result], { type: 'application/octet-stream' }), 'scene.glb');
				} else {
					const output = JSON.stringify(result, null, 2);
					me.save(new Blob([output], { type: 'text/plain' }), 'scene.gltf');
				}

				// 显示辅助类obj
				scene.traverse(i => {
					if (i.userData.type === WORDS.OBJNAME.HELPER_PREFIX || i.userData.type === WORDS.OBJNAME.MODEL_DATALINE) {
						i.visible = true
					}
				})

				// me.resetScene()
			}, function () {
			},
			exPortOptions
		)


	}

	/**
	 * 重置场景（清空并添加辅助对象）
	 */
	resetScene() {
		const me = this
		if (!scene) {
			return
		}
		// 清空objs
		if (scene.children.length > 0) {
			// clear会清除所有add过的对象，so慎用 scene.clear()
			scene.clear()
		}

		me.addAidedObjs()
	}


	/**
	 * 新增连接线
	 */
	addDataLine(params: DataLineParams) {
		const me = this
		me.stopOperate()
		me._curOperation = 'addDataLine'
		me.showhideAidedObjs(true)

		// 添加鼠标悬浮球体
		const material = new THREE.MeshBasicMaterial({ color: 'yellow', opacity: 0.5, transparent: true });
		me._thatsAddingDataLine.sphere = new THREE.Mesh(new THREE.SphereGeometry(3), material)
		me._thatsAddingDataLine.sphere.position.setY(SETTINGS.SPHERE.OFFSET_Y)
		scene.add(me._thatsAddingDataLine.sphere)

		me._thatsAddingDataLine.bodyLine = new Line2(new LineGeometry(), new LineMaterial({
			color: params.color,
			worldUnits: true,
			linewidth: 2
		}))

		me._thatsAddingDataLine.headLine = new Line2(new LineGeometry(), new LineMaterial({
			color: params.color,
			worldUnits: true,
			linewidth: 2
		}))
		me._thatsAddingDataLine.params = params

		scene.add(me._thatsAddingDataLine.bodyLine)
		scene.add(me._thatsAddingDataLine.headLine)
	}

	/**
	 * 导出架构树
	 * @param fileName 
	 */
	exportFrameTree(fileName = 'frameTree') {
		const me = this
		if (me._frame.platforms.size === 0) {
			console.error(WORDS.ERROR.NONE_PLATFORM)
		} else {
			me.save(new Blob([JSON.stringify(me._frame.toJSON())], { type: 'text/json' }), `${fileName}.json`)
		}
	}

	/**
	 * 新建平台层
	 * @param offY 平台偏离量
	 */
	createPlatform() {
		const me = this
		me.stopOperate()
		// const planeGeo = new THREE.PlaneGeometry(400, 200)

		// planeGeo.rotateX(-Math.PI / 2)

		const planeGeo = new THREE.BoxGeometry(400, SETTINGS.PLANE.HEIGHT, 200)

		const faceTex = new THREE.TextureLoader().load(
			"./textures/platform.jpg",
			// function (tex) {
			// 	tex.needsUpdate = true;
			// 	tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
			// 	tex.repeat.set(2, 2);
			// }
		);

		const faceMtl = new THREE.MeshBasicMaterial({
			side: DoubleSide,
			color: 'grey',// 颜色值无效 0x04316c
			map: faceTex,
			opacity: 0.8,
			transparent: true,
		})

		const planeMesh = new THREE.Mesh(planeGeo, faceMtl)//[edgeMtl, edgeMtl, faceMtl, faceMtl, edgeMtl, edgeMtl]; //前后顶底左右面
		planeMesh.position.setY(SETTINGS.PLANE.OFFSET_Y)
		// planeMesh.position.setY(0)// 避免dataLine 在同一个Y纬度，影响展示效果
		const plane = new Plane(planeMesh, {
			textureUrl: "./textures/platform.jpg",
			width: 400,
			depth: 200,
			color: 'grey',
			opacity: 0.8
		})
		const p = me._frame.addPlatform(plane)
		me._curPlatform = p
		scene.add(p.plane.obj)

	}

	editModelAttrById(id: string, attr: object) {
		const obj = scene.getObjectByName(id)
		obj && this.editModelAttr(obj, attr)
	}

	editModelAttr(model: Object3D, attr: object) {
		model.userData.attr = attr
	}

	setSelectedModel(model: DataLine | Device | null) {
		if (!model) {
			this._clearSelectedModelEffect()
			const children = this._gui!.gui.children.map(i => { return i })
			children.map(i => { i.destroy() })
			this._gui?.setTitle('')
		} else {


			this._gui?.setTitle(model.params.id || '')
			model.obj.userData.attr = model.obj.userData.attr || ''// 需要提前告知GUI，attr什么类型，否则无法新增control
			this._gui?.addStrCtl(model.obj.userData, 'attr')


			switch (model.type) {
				case WORDS.OBJNAME.MODEL_DATALINE:
					// 选中高亮


					this._gui?.addNumCtl(model.obj.material, 'linewidth', 1, 5)
					this._gui?.addColorCtl(model.obj.material, 'color')
					break;
				case WORDS.OBJNAME.MODEL_DEVICE:
					this._gui?.addNumCtl(model.obj.position, 'x', -200, 200, 10)
					this._gui?.addNumCtl(model.obj.position, 'z', -200, 200, 10)
					model.obj.userData.text = model.obj.userData.text || ''// 需要提前告知GUI，attr什么类型，否则无法新增control

					this._gui?.addTextCtl(model.obj.userData, 'text', (text) => {
						// model.text

						// 创建文本纹理
						var fontSize = 14;
						var textColor = "#ffffff";
						var canvas = document.createElement("canvas");
						var context = canvas.getContext("2d")!
						context.font = fontSize + "px 宋体";
						var textWidth = context.measureText(text).width;
						canvas.width = textWidth;
						canvas.height = fontSize + 2;
						context.font = fontSize + "px 宋体";
						context.fillStyle = textColor;
						context.fillText(text, 0, fontSize);
						// 创建文本纹理对象
						var texture = new THREE.CanvasTexture(canvas);
						model.text!.material.map = texture
						model.text!.scale.setX(textWidth)
					})
					break;
				default:
					break;
			}



		}
		this._selectedModel = model
	}

	delModel(id: string, type: string, platformIndex?: number) {
		// 框架中移除
		if (platformIndex !== undefined) {
			const p = this._frame.getPlatform(platformIndex)
			p && p.removeByIdType(id, type)
		}

		// 实体移除
		const obj = scene.getObjectByName(id)
		obj && scene.remove(obj)
	}

	// clearSelectedModel


	/////

	save(blob: Blob, filename: string) {
		link.href = URL.createObjectURL(blob);
		link.download = filename;
		link.click();

	}



	// removeObj(filter: (name: string) => boolean) {
	// 	// 遍历场景中的对象
	// 	for (let i = scene.children.length - 1; i >= 0; i--) {
	// 		const object = scene.children[i];

	// 		// 根据规则进行判断
	// 		if (filter(object.name)) {
	// 			// 移除对象
	// 			scene.remove(object);
	// 		}
	// 	}
	// }

	/**
	 * 添加辅助对象
	 */
	addAidedObjs() {
		const me = this

		// 灯光
		const ambientLight = new THREE.AmbientLight(0xffffff, 2); // 环境光
		// ambientLight.position.setY(100)
		scene.add(ambientLight)

		// 网格
		const grid1 = new THREE.GridHelper(200, 20)
		grid1.position.set(100, SETTINGS.GRID.OFFSET_Y, 0)
		grid1.material.opacity = SETTINGS.GRID.OPACITY
		grid1.material.transparent = true
		grid1.userData.type = WORDS.OBJNAME.HELPER_PREFIX
		scene.add(grid1);
		const grid2 = new THREE.GridHelper(200, 20)
		grid2.position.set(-100, SETTINGS.GRID.OFFSET_Y, 0)
		grid2.material.opacity = SETTINGS.GRID.OPACITY
		grid2.material.transparent = true
		grid2.userData.type = WORDS.OBJNAME.HELPER_PREFIX
		scene.add(grid2);

		// 平面（hide|用于鼠标事件交互）
		const planeGeo = new THREE.PlaneGeometry(400, 200)
		planeGeo.rotateX(- Math.PI / 2);
		me._aidedPlane = new THREE.Mesh(planeGeo, new THREE.MeshBasicMaterial({ visible: false }))
		me._aidedPlane.userData.type = WORDS.OBJNAME.HELPER_PREFIX
		scene.add(me._aidedPlane);

		// 坐标轴
		const arrowPos = new THREE.Vector3(0, 1, 0)
		const arrowX = new THREE.ArrowHelper(new THREE.Vector3(1, 0, 0), arrowPos, 100, 'red', 20, 10)
		const arrowY = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), arrowPos, 100, 'yellow', 20, 10)
		const arrowZ = new THREE.ArrowHelper(new THREE.Vector3(0, 0, 1), arrowPos, 100, 'blue', 20, 10)
		arrowX.userData.type = WORDS.OBJNAME.HELPER_PREFIX
		arrowY.userData.type = WORDS.OBJNAME.HELPER_PREFIX
		arrowZ.userData.type = WORDS.OBJNAME.HELPER_PREFIX
		scene.add(arrowX)
		scene.add(arrowY)
		scene.add(arrowZ)

		// 线悬浮样式
		me._aidedLine4highlight = new Line2(new LineGeometry(), new LineMaterial({
			color: new THREE.Color(0, 1, 1),
			worldUnits: true,
			linewidth: 3
		}))
		me._aidedLine4highlight.userData.type = WORDS.OBJNAME.HELPER_PREFIX
		me._aidedLine4highlight.visible = false
		scene.add(me._aidedLine4highlight)

		// 线悬浮样式
		me._aidedLine4selected = new Line2(new LineGeometry(), new LineMaterial({
			color: new THREE.Color(0, 1, 1),
			worldUnits: true,
			linewidth: 4
		}))
		me._aidedLine4selected.userData.type = WORDS.OBJNAME.HELPER_PREFIX
		me._aidedLine4selected.visible = false
		scene.add(me._aidedLine4selected)

	}

	showhideAidedObjs(visible: boolean) {
		scene.traverse(i => {
			if (i.userData.type === WORDS.OBJNAME.HELPER_PREFIX) {
				i.visible = visible
			}
		})
	}

	stopOperate() {
		const me = this

		// 移除move model
		// me._mousemoveModel && scene.remove(me._mousemoveModel)
		// me._curModel && scene.remove(me._curModel)
		switch (me._curOperation) {
			case 'addDevice':
				me._thatsAddingDevice.obj && scene.remove(me._thatsAddingDevice.obj)
				me._thatsAddingDevice.obj = undefined
				me._thatsAddingDevice.params = undefined
				break;
			case 'addDataLine':
				me._thatsAddingDataLine.bodyLine && scene.remove(me._thatsAddingDataLine.bodyLine)
				me._thatsAddingDataLine.bodyLine = undefined
				me._thatsAddingDataLine.headLine && scene.remove(me._thatsAddingDataLine.headLine)
				me._thatsAddingDataLine.headLine = undefined
				me._thatsAddingDataLine.sphere && scene.remove(me._thatsAddingDataLine.sphere)
				me._thatsAddingDataLine.sphere = undefined
				me._thatsAddingDataLine.params = undefined
				break;
			default:
				break;
		}
		me._curOperation = ''
		me.showhideAidedObjs(false)
	}

	/////


	/**
	 * <<<鼠标悬浮事件<<<
	 */

	private _mousemoveWhenNullOp(e: MouseEvent) {
		const me = this
		// 设备+连线+
		if (!me._curPlatform) {
			return
		}

		pointer.set((e.offsetX / me._canvas.width) * 2 - 1, - (e.offsetY / me._canvas.height) * 2 + 1);
		raycaster.setFromCamera(pointer, camera);

		const objects: Object3D[] = Array.from(me._curPlatform.devices.values()).map(i => { return i.obj })
		objects.push(...Array.from(me._curPlatform.dataLines.values()).map(i => { return i.obj }))
		const intersects = raycaster.intersectObjects(objects, false);

		if (intersects.length > 0) {
			const intersect = intersects[0]
			// 悬浮的不为同一个则关闭之前的高亮，对新的高亮
			if (intersect.object.name !== me._mousemoveObj?.name) {
				// 若有悬浮物，关闭之前的高亮
				closeHighlight()

				// 高亮新的
				if (intersect.object.userData.type === WORDS.OBJNAME.MODEL_DEVICE) {
					me._outlinePass!.selectedObjects = [intersect.object]
				} else if (intersect.object.userData.type === WORDS.OBJNAME.MODEL_DATALINE) {
					const line2 = intersect.object as Line2
					me._aidedLine4highlight!.geometry = line2.geometry.clone()
					me._aidedLine4highlight!.visible = true
				}

				me._mousemoveObj = intersect.object
			}
		} else {
			closeHighlight()
		}

		/**
		 * 关闭当前高亮的对象
		 * @param obj 
		 */
		function closeHighlight() {
			if (me._mousemoveObj) {
				// 根据是 连线/设备 执行不同关闭
				if (me._mousemoveObj.userData.type === WORDS.OBJNAME.MODEL_DEVICE) {
					me._outlinePass!.selectedObjects = [];
				} else if (me._mousemoveObj.userData.type === WORDS.OBJNAME.MODEL_DATALINE) {
					me._aidedLine4highlight!.visible = false
				}
				me._mousemoveObj = undefined
			}
		}
	}

	private _mousemoveWhenAddDevice(e: MouseEvent) {
		const me = this
		if (!me._thatsAddingDevice.obj || !me._aidedPlane) {
			throw new Error("");
		}

		pointer.set((e.offsetX / me._canvas.width) * 2 - 1, - (e.offsetY / me._canvas.height) * 2 + 1);
		raycaster.setFromCamera(pointer, camera);

		const intersects = raycaster.intersectObjects([me._aidedPlane], false);

		if (intersects.length > 0) {
			const intersect = intersects[0]
			if (intersect) {
				me._thatsAddingDevice.obj.position.set(Math.round(intersect.point.x / 10) * 10, SETTINGS.DEVICE.OFFSET_Y, Math.round(intersect.point.z / 10) * 10)
			}
		}
	}

	private _mousemoveWhenAddDataLine(e: MouseEvent) {
		const me = this

		if (!me._thatsAddingDataLine.sphere || !me._aidedPlane || !me._thatsAddingDataLine.headLine || !me._thatsAddingDataLine.params) {
			return
		}

		pointer.set((e.offsetX / me._canvas.width) * 2 - 1, - (e.offsetY / me._canvas.height) * 2 + 1);

		raycaster.setFromCamera(pointer, camera);

		const intersects = raycaster.intersectObjects([me._aidedPlane], false);

		if (intersects.length > 0) {
			const intersect = intersects[0]
			if (intersect) {
				me._thatsAddingDataLine.sphere.position.setX(Math.round(intersect.point.x / 10) * 10)
				me._thatsAddingDataLine.sphere.position.setZ(Math.round(intersect.point.z / 10) * 10)

				if (me._thatsAddingDataLine.params.points.length === 0) {

					// me._mousemoveModel2.visible = false
				} else {
					me._thatsAddingDataLine.headLine.geometry = new LineGeometry();
					// 最后一个点和当前悬浮点
					const point1 = me._thatsAddingDataLine.params.points[me._thatsAddingDataLine.params.points.length - 1]
					const point2 = [me._thatsAddingDataLine.sphere.position.x, 0, me._thatsAddingDataLine.sphere.position.z];
					me._thatsAddingDataLine.headLine.geometry.setPositions([point1[0], point1[1], point1[2], point2[0], point2[1], point2[2]])
					// me._mousemoveModel2.visible = true
				}
			}
		}
	}

	/**
	 * >>>鼠标悬浮事件>>>
	 */

	/**
	 * <<<双击事件<<<
	 */

	private _dblclickWhenAddDataLine(e: MouseEvent) {
		const me = this
		if (!me._aidedPlane || !me._thatsAddingDataLine.bodyLine || !me._thatsAddingDataLine.params) {
			return
		}
		pointer.set((e.offsetX / me._canvas.width) * 2 - 1, - (e.offsetY / me._canvas.height) * 2 + 1);

		raycaster.setFromCamera(pointer, camera);

		const intersects = raycaster.intersectObjects([me._aidedPlane], true);

		if (intersects.length > 0) {
			if (intersects.length === 1) {
				const intersect = intersects[0]
				const newPoint = new Vector3()
				newPoint.setX(Math.round(intersect.point.x / 10) * 10)
				newPoint.setZ(Math.round(intersect.point.z / 10) * 10)
				me._thatsAddingDataLine.params.points.push([newPoint.x, SETTINGS.DATALINE.OFFSET_Y, newPoint.z]);
				if (me._thatsAddingDataLine.params.points.length > 1) {
					me._thatsAddingDataLine.bodyLine.geometry = new LineGeometry();
					me._thatsAddingDataLine.bodyLine.geometry.setPositions(me._thatsAddingDataLine.params.points.flat())
				} else if (me._thatsAddingDataLine.params.points.length === 1) {
				}
			}
		}





		// curModel回归到addDataLine时
		// 先简单处理成关闭
	}

	private _dblclickWhenAddDevice(e: MouseEvent) {
		const me = this
		if (!me._aidedPlane || !me._thatsAddingDevice) {
			return
		}
		pointer.set((e.offsetX / me._canvas.width) * 2 - 1, - (e.offsetY / me._canvas.height) * 2 + 1);

		raycaster.setFromCamera(pointer, camera);

		const intersects = raycaster.intersectObjects([me._aidedPlane], true);

		if (intersects.length > 0) {
			if (intersects.length === 1) {
				if (me._thatsAddingDevice.obj && me._thatsAddingDevice.params) {
					const platform = me._frame.getCurPlatform()
					// 标注
					const textObj = me._text("服务器")
					// const params: DeviceParams = {
					// 	width: me._thatsAddingDevice.model.params.width,
					// 	height: me._thatsAddingDevice.model.params.height,
					// 	depth: me._thatsAddingDevice.model.params.depth,
					// 	color: me._thatsAddingDevice.model.params.color,
					// 	opacity: me._thatsAddingDevice.model.params.opacity,
					// 	position: me._thatsAddingDevice.obj.position.toArray()
					// }

					const deviceToAdd = new Device(Helper.deepClone(me._thatsAddingDevice.obj) as Mesh<BoxGeometry, MeshBasicMaterial>, Helper.cloneObject(me._thatsAddingDevice.params))
					deviceToAdd.setOpacity(me._thatsAddingDevice.params.opacity)
					platform && platform.addDevice(deviceToAdd)
					// device.text?.position.copy(device.obj.position)
					// device.text?.position.setY(50)
					scene.add(deviceToAdd.obj)
					// scene.add(device.text!)
				}
			}
		}
	}

	/**
	 * >>>双击事件>>>
	 */


	private _clickWhenNullOp(e: MouseEvent) {
		const me = this

		pointer.set((e.offsetX / me._canvas.width) * 2 - 1, - (e.offsetY / me._canvas.height) * 2 + 1);

		raycaster.setFromCamera(pointer, camera);

		if (!me._curPlatform) {
			return
		}
		const objects: Object3D[] = Array.from(me._curPlatform.devices.values()).map(i => { return i.obj })
		objects.push(...Array.from(me._curPlatform.dataLines.values()).map(i => { return i.obj }))
		const intersects = raycaster.intersectObjects(objects, false);

		if (intersects.length > 0) {
			const intersect = intersects[0]
			// 悬浮的不为同一个则关闭之前的高亮，对新的高亮
			if (intersect.object.name !== me._selectedModel?.obj.name) {
				// 若有
				me.setSelectedModel(null)

				// 高亮新的
				if (intersect.object.userData.type === WORDS.OBJNAME.MODEL_DEVICE) {
					me._outlinePassS!.selectedObjects = [intersect.object]
					me.setSelectedModel(me._curPlatform.devices.get(intersect.object.name) || null)
				} else if (intersect.object.userData.type === WORDS.OBJNAME.MODEL_DATALINE) {
					const line2 = intersect.object as Line2
					me._aidedLine4selected!.geometry = line2.geometry.clone()
					me._aidedLine4selected!.visible = true
					me.setSelectedModel(me._curPlatform.dataLines.get(intersect.object.name) || null)
				}
			}
		} else {
			me.setSelectedModel(null)
		}

	}

	/**
	 * >>>单击事件>>>
	 */


	private _onWindowResize() {
		camera.aspect = this._canvas.width / this._canvas.height
		camera.updateProjectionMatrix();

		renderer.setSize(this._canvas.width, this._canvas.height)
		this._composer && this._composer.setSize(this._canvas.width, this._canvas.height)
	}

	private _keyupWhenNullOp(e: KeyboardEvent) {
		const me = this
		switch (e.key) {
			case 'Delete':
				const id = me._selectedModel?.id
				const type = me._selectedModel?.type
				const index = me._selectedModel?.platformIndex
				me.setSelectedModel(null)
				if (id && type) {
					me.delModel(id, type, index)
				}
				break;
			default:
				break;
		}
	}

	private _keyupWhenAddDevice(e: KeyboardEvent) {
		const me = this
		switch (e.key) {
			case 'Shift':
				break;
			case 'Escape':
				me.stopOperate.bind(me)()
				break;
		}

	}

	private _keyupWhenAddDataLine(e: KeyboardEvent) {
		const me = this
		switch (e.key) {
			case 'Escape':
				// 记录当前添加的线
				if (me._curPlatform && me._thatsAddingDataLine.bodyLine && me._thatsAddingDataLine.params && me._thatsAddingDataLine.params.points.length > 1) {

					const modelToAdd = Helper.deepClone(me._thatsAddingDataLine.bodyLine) as Line2
					const params: DataLineParams = {
						color: Helper.getHexColorStr(modelToAdd.material.color),
						width: modelToAdd.material.linewidth,
						points: [...me._thatsAddingDataLine.params.points],
						opacity: modelToAdd.material.opacity
					}
					const dataLine = new DataLine(modelToAdd, params)
					me._curPlatform.addDataLine(dataLine)

					scene.add(dataLine.obj)
				}
				me.stopOperate()
				break;
		}
	}

	/**
	 * --- 事件 ---
	 */

	private _mousemoveEvent(e: MouseEvent) {
		this._mousemoveEventInstance = null
		switch (this._curOperation) {
			case '':
				this._mousemoveEventInstance = this._mousemoveWhenNullOp
				break;
			case 'addDevice':
				this._mousemoveEventInstance = this._mousemoveWhenAddDevice
				break;
			// case 'editWirFrame':
			// 	this._mousemoveEventInstance = this._mousemoveWhenWireFrame
			// 	break;
			case 'addDataLine':
				this._mousemoveEventInstance = this._mousemoveWhenAddDataLine
				break;
			default:
				break;
		}
		// document事件回调中this指向document所以bind
		this._mousemoveEventInstance && this._mousemoveEventInstance(e)
	}

	private _dblclickEvent(e: MouseEvent) {
		this._dblclickEventInstance = null
		switch (this._curOperation) {
			case 'addDevice':
				this._dblclickEventInstance = this._dblclickWhenAddDevice
				break;
			// case 'editWirFrame':
			// 	this._dblclickEventInstance = this._dblclickWhenAddModel
			// 	break;
			case 'addDataLine':
				this._dblclickEventInstance = this._dblclickWhenAddDataLine
				break;
			default:
				break;
		}
		this._dblclickEventInstance && this._dblclickEventInstance(e)
	}

	private _clickEvent(e: MouseEvent) {//
		this._clickEventInstance = null
		switch (this._curOperation) {
			case '':
				this._clickEventInstance = this._clickWhenNullOp
				break;

			default:
				break;
		}
		this._clickEventInstance && this._clickEventInstance(e)
	}

	private _keyupEvent(e: KeyboardEvent) {
		this._keyUpEventInstance = null
		switch (this._curOperation) {
			case '':
				this._keyUpEventInstance = this._keyupWhenNullOp
				break;
			case 'addDevice':
				this._keyUpEventInstance = this._keyupWhenAddDevice
				break;
			// case 'editWirFrame':
			// 	break;
			case 'addDataLine':
				this._keyUpEventInstance = this._keyupWhenAddDataLine
				break;
			default:
				break;
		}

		this._keyUpEventInstance && this._keyUpEventInstance(e)
	}

	/**
	 * 生成高亮球
	 * @param xyzs 坐标
	 * @param color 颜色
	 * @param radius r
	 * @returns 高亮球集合
	 */
	private _highlightSphere(xyzs: [number, number, number][], color: string, radius = 3) {
		const spheres:Mesh<SphereGeometry, MeshBasicMaterial>[] = []
		xyzs.forEach(xyz => {
			const sphere = new Mesh<SphereGeometry, MeshBasicMaterial>()
			sphere.geometry = new SphereGeometry(radius)
			sphere.material = new MeshBasicMaterial({
				color,
				opacity: 0.5,
				transparent:true
			})
			sphere.position.set(xyz[0], xyz[1], xyz[2])
			spheres.push(sphere)
		})
		
		return spheres
	}


	_render() {
		const me = this

		controls.update();
		me._composer && me._composer.render();
		requestAnimationFrame(me._render.bind(me));
		// renderer.render(scene, camera);
	}


	/**
	 * 清除当前选择对象的特效
	 */
	_clearSelectedModelEffect() {
		const me = this
		if (me._selectedModel) {
			// 根据是 连线/设备 执行不同关闭
			if (me._selectedModel.type === WORDS.OBJNAME.MODEL_DEVICE) {
				me._outlinePassS!.selectedObjects = []
			} else if (me._selectedModel.type === WORDS.OBJNAME.MODEL_DATALINE) {
				me._aidedLine4selected!.visible = false
			}
		}
	}

	_text(content: string,) {

		// 创建文本纹理
		var text = content;
		var fontSize = 14;
		var textColor = "#ffffff";
		var canvas = document.createElement("canvas") as HTMLCanvasElement
		var context = canvas.getContext("2d")!
		context.font = fontSize + "px 宋体";
		var textWidth = context.measureText(text).width;
		canvas.width = textWidth;
		canvas.height = fontSize + 2;
		context.font = fontSize + "px 宋体";
		context.fillStyle = textColor;
		context.fillText(text, 0, fontSize);

		// 创建文本纹理对象
		var texture = new THREE.CanvasTexture(canvas);

		// 创建Sprite对象
		var spriteMaterial = new THREE.SpriteMaterial({ map: texture });
		var sprite = new THREE.Sprite(spriteMaterial);

		// 设置Sprite对象的大小
		sprite.scale.set(textWidth, fontSize, 1)
		// sprite.position.set(0, 0, 0)

		// 将Sprite对象添加到场景中
		return sprite
	}

}

export { main }

let mainC = new main()
mainC.init()
window["mainC"] = mainC